{-  Copyright (C) 2014 Mark W Pearse  
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

The main.c program distributes N tasks to N Epiphany cores in parallel and
aggregates the result after all cores have completed to produce the final 
result.
-}

module Main where

import E_Data
import E_rawAPI
import E_API
import EpuAlloc
import EpuCode
import Control.Monad (liftM)

n = 4096
cores = 16
baseAddr = EpuAddr 0x2000
coreProgSrc = "epu_dot"

main = do
-- prepare data that will be used on each Epiphany core
    let defs = [EpuDef "N" n, EpuDef "CORES" cores]

    let ones = replicate (quot n cores) (1::Int)
    let zero = replicate 1 (0::Int)
    let ebs = [EpuBlock "a" ones, 		-- parts of a matrix
               EpuBlock "b" ones, 		-- parts of b matrix
               EpuBlock "c" zero, 		-- Result
               EpuBlock "d" zero]		-- Done
    let epudata = allocate baseAddr ebs
    putStrLn $ show epudata
    let refC = findBlock epudata "c"
    let refD = findBlock epudata "d"

-- compile c program for each core using these allocations
    maybeCP <- compileForEpu defs epudata coreProgSrc
    case maybeCP of
      Nothing -> return ()
      Just coreProg -> 

-- set up epiphany environment
        withEpiphanyInfo (\pInfo -> do
           putStrLn $ "Calculating sum of products of two integer vectors of length " ++ show n ++ " initalized to all 1's using " ++ show cores ++ " cores."
           let origin = EpuPos 0 0
           let size = platformSize pInfo
           withGroup origin size (\groupref -> do
--               _ <- e_set_loader_verbosity 1
               let copyTo = (\pos -> writeEpuData groupref pos epudata )
               mapM_  copyTo $ (allcores pInfo) 		-- copy all data to cores

               let readInt epuBlock pos = (liftM head) $ readEpuBlock groupref pos epuBlock
               let readSum epuBlock = (liftM sum) $ mapM (readInt epuBlock) (allcores pInfo)
               let nDone = readSum refD 
               epuRunProg coreProg groupref size           -- load and run on 
               
               spinLock (>= cores) nDone 			-- Wait until all cores are done
               sop <- readSum refC
               putStrLn $ "Sum of Product is " ++ show sop	-- Print out result
             )
           )

